﻿using System;
using System.Collections.Generic;
using MarriageFertility.Helpers;
using MarriageFertility.Mcm;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.ComponentInterfaces;
using TaleWorlds.CampaignSystem.GameComponents;

namespace MarriageFertility.Models;

public class MfMarriageModel : MarriageModel
{
    private readonly MarriageModel _previousModel;
    public MfMarriageModel(MarriageModel previousModel)
    {
        if (previousModel == null)
        {
            throw new ArgumentNullException(nameof(previousModel), "Previous MarriageModel cannot be null.");
        }
        _previousModel = previousModel;
    }
    
    private float BaseMarriageChanceForNPCs => MCMSettings.Instance.BaseMarriageChanceForNPCs / 100;
    public override int MinimumMarriageAgeMale => MCMSettings.Instance.MinimumMarriageAgeMale;
    public override int MinimumMarriageAgeFemale => MCMSettings.Instance.MinimumMarriageAgeFeMale;

    public override bool IsCoupleSuitableForMarriage(Hero firstHero, Hero secondHero)
    {
        if (!IsClanSuitableForMarriage(firstHero.Clan) || !IsClanSuitableForMarriage(secondHero.Clan))
            return false;
        
        if (firstHero.Clan?.Leader == firstHero && secondHero.Clan?.Leader == secondHero)
            return false;
        
        if (!Helper.GenderSuitable(firstHero, secondHero))
            return false;
        
        if (!MCMSettings.Instance.EnableRelatedMarriage && AreHeroesRelated(firstHero, secondHero, 3))
            return false;
        
        if (!firstHero.CanMarry() || !secondHero.CanMarry())
            return false;
        
        Hero firstHeroCourtedTarget = Romance.GetCourtedHeroInOtherClan(firstHero, secondHero);
        if (firstHeroCourtedTarget != null && firstHeroCourtedTarget != secondHero)
            return false;

        Hero secondHeroCourtedTarget = Romance.GetCourtedHeroInOtherClan(secondHero, firstHero);
        if (secondHeroCourtedTarget != null && secondHeroCourtedTarget != firstHero)
            return false;

        return true;
    }

    public override bool IsClanSuitableForMarriage(Clan clan)
    {
        if (clan == null || _previousModel == null)
        {
            return false;
        }
        try
        {
           return _previousModel.IsClanSuitableForMarriage(clan);
        }
        catch (Exception e)
        {
            return false;
        }
    }
    
    public override float NpcCoupleMarriageChance(Hero firstHero, Hero secondHero)
    {
        if (!MCMSettings.Instance.EnableNpcMarriageChance)
        {
            return _previousModel.NpcCoupleMarriageChance(firstHero, secondHero);
        }

        if (!IsCoupleSuitableForMarriage(firstHero, secondHero))
        {
            return 0.0f;
        }

        float ageFactorFirstHero = (firstHero.Age - GetHeroMinMarriageAge(firstHero)) / 50.0f;
        float ageFactorSecondHero = (secondHero.Age - GetHeroMinMarriageAge(secondHero)) / 50.0f;
        float ageDifferenceFactor = 1.0f - TaleWorlds.Library.MathF.Abs(secondHero.Age - firstHero.Age) / 50.0f;

        float baseMarriageChance = BaseMarriageChanceForNPCs * (1.0f + ageFactorFirstHero) * (1.0f + ageFactorSecondHero) * ageDifferenceFactor;

        if (!MCMSettings.Instance.IgnoreKingdom && firstHero.Clan.Kingdom != secondHero.Clan.Kingdom)
        {
            baseMarriageChance = 0.0f;
        }

        float relationFactor = 0.5f + firstHero.Clan.GetRelationWithClan(secondHero.Clan) / 200.0f;
        if (!MCMSettings.Instance.IgnoreClan && firstHero.Clan != secondHero.Clan)
        {
            relationFactor = 0.0f;
        }

        return baseMarriageChance * relationFactor;
    }


    private int GetHeroMinMarriageAge(Hero hero) => hero.IsFemale ? MinimumMarriageAgeFemale : MinimumMarriageAgeMale;

    public override bool ShouldNpcMarriageBetweenClansBeAllowed(
        Clan consideringClan,
        Clan targetClan)
    {
        return _previousModel.ShouldNpcMarriageBetweenClansBeAllowed(consideringClan, targetClan);
    }
    
    public override List<Hero> GetAdultChildrenSuitableForMarriage(Hero hero)
    {
        return _previousModel.GetAdultChildrenSuitableForMarriage(hero);
    }

    private bool AreHeroesRelatedAux1(Hero firstHero, Hero secondHero, int ancestorDepth)
    {
        if (firstHero == secondHero)
            return true;
        if (ancestorDepth <= 0)
            return false;
        if (secondHero.Mother != null && AreHeroesRelatedAux1(firstHero, secondHero.Mother, ancestorDepth - 1))
            return true;
        return secondHero.Father != null && AreHeroesRelatedAux1(firstHero, secondHero.Father, ancestorDepth - 1);
    }

    private bool AreHeroesRelatedAux2(
        Hero firstHero,
        Hero secondHero,
        int ancestorDepth,
        int secondAncestorDepth)
    {
        if (AreHeroesRelatedAux1(firstHero, secondHero, secondAncestorDepth))
            return true;
        if (ancestorDepth <= 0)
            return false;
        if (firstHero.Mother != null &&
            AreHeroesRelatedAux2(firstHero.Mother, secondHero, ancestorDepth - 1, secondAncestorDepth))
            return true;
        return firstHero.Father != null &&
               AreHeroesRelatedAux2(firstHero.Father, secondHero, ancestorDepth - 1, secondAncestorDepth);
    }

    private bool AreHeroesRelated(Hero firstHero, Hero secondHero, int ancestorDepth) =>
        AreHeroesRelatedAux2(firstHero, secondHero, ancestorDepth, ancestorDepth);

    public override int GetEffectiveRelationIncrease(Hero firstHero, Hero secondHero)
    {
        return _previousModel.GetEffectiveRelationIncrease(firstHero, secondHero);
    }

    public override bool IsSuitableForMarriage(Hero maidenOrSuitor)
    {
        if (maidenOrSuitor == null) return false;
        if (maidenOrSuitor == Hero.MainHero) return true;
        if (MCMSettings.Instance.OnlyPlayerMarryMore && maidenOrSuitor.Spouse?.IsAlive == true) return false;
        if (!maidenOrSuitor.IsActive || !maidenOrSuitor.CanMarrySpouse() || !maidenOrSuitor.IsLord ||
            maidenOrSuitor.IsMinorFactionHero || maidenOrSuitor.IsNotable || maidenOrSuitor.IsTemplate ||
            maidenOrSuitor.PartyBelongedTo?.MapEvent != null || maidenOrSuitor.PartyBelongedTo?.Army != null)
            return false;
        return maidenOrSuitor.IsFemale
            ? maidenOrSuitor.CharacterObject.Age >= MinimumMarriageAgeFemale
            : maidenOrSuitor.CharacterObject.Age >= MinimumMarriageAgeMale;
    }

    public override Clan GetClanAfterMarriage(Hero firstHero, Hero secondHero)
    {
        if (MCMSettings.Instance.JoinPlayerClan && (firstHero.IsPlayerClan() || secondHero.IsPlayerClan())) return Clan.PlayerClan;
        return _previousModel.GetClanAfterMarriage(firstHero,secondHero);
    }
}